﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using FluentBootstrap;
using HtmlAgilityPack;

/*
 http://www.aspsnippets.com/Articles/Catching-Handling-and-displaying-Exceptions-and-Errors-when-using-jQuery-AJAX-and-WebMethod-in-ASPNet.aspx
 */
namespace GrayParrot.Web
{
    public enum FormView
    {
        Vertical,
        Inline,
        Horizontal
    }

    #region Inner Properties...
    /// <summary>
    /// Column class definition...
    /// </summary>
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public abstract class TagBase
    {
        public string RefId { get; set; }
        public bool Visible { get; set; }

        public TagBase()
        {
            Visible = true;
        }
    }

    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class Input : TagBase
    {
        public Icon HasGroupBefore { get; set; }
        public Icon HasGroupAfter { get; set; }
        public string Placeholder { get; set; }
        public string Label { get; set; }

        public Input()
        {
            HasGroupAfter = Icon.None;
            HasGroupBefore = Icon.None;
        }
    }

    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class Form : TagBase
    {
        public FormView View { get; set; }
        public Form()
        {
        }
    }

    /// <summary>
    /// Elements Configuration class...
    /// </summary>
    public class Elements
    {
        /// <summary>
        /// Gets or sets the columns.
        /// </summary>
        /// <value>
        /// The columns.
        /// </value>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public List<TagBase> Tags { get; set; }

        ///// <summary>
        ///// Gets or sets the key.
        ///// </summary>
        ///// <value>
        ///// The key.
        ///// </value>
        //public string Key { get; set; }

        //public string SortKey { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnsConfig"/> class.
        /// </summary>
        public Elements()
        {
            this.Tags = new List<TagBase>();
        }
    }
    #endregion

    [DefaultProperty("Text")]
    [ToolboxData("<{0}:Bootstrapminator runat=server></{0}:Bootstrapminator>")]
    [ParseChildren(true, "Content")]
    public class Bootstrapminator : WebControl, INamingContainer
    {
        private List<Control> m_internalControlCollection = null;
        private Elements m_elements = new Elements();

        [Bindable(true)]
        [Category("Bootstrapminator")]
        [DefaultValue(null)]
        [Localizable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)]
        public Elements Conversion
        {
            get { return m_elements; }
            set { m_elements = value; }
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(Bootstrapminator))]
        [TemplateInstance(TemplateInstance.Single)]
        public virtual ITemplate Content { get; set; }

        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string Text
        {
            get
            {
                String s = (String)ViewState["Text"];
                return ((s == null) ? String.Empty : s);
            }

            set
            {
                ViewState["Text"] = value;
            }
        }

        public bool UseBootstrap { get; set; }

        public Bootstrapminator()
        {
            if (m_internalControlCollection == null)
            {
                m_internalControlCollection = new List<Control>();
            }  
        }

        //protected override void RenderContents(HtmlTextWriter output)
        //{
        //    //string m_newHtml = string.Empty;

        //    //StringBuilder sb = new StringBuilder();
        //    //HtmlTextWriter tw = new HtmlTextWriter(new StringWriter(sb));
        //    //base.Render(output);

        //    //((GrayParrot.Web.UI.Page)this.Page).Render(output);

        //    //m_newHtml = sb.ToString();

        //    //if (this.Page.GetType() == typeof(GrayParrot.Web.UI.Page))
        //    //{
        //    //    m_newHtml = ((GrayParrot.Web.UI.Page)this.Page).InnerHtml;

        //    //    string p = Decorate(m_newHtml);

        //    //    output.Write(p);
        //    //}


        //    //string m_newHtml = string.Empty;


            
                                   
        //    //m_newHtml = helper.Input("input-name").ToHtmlString().Replace("\r\n", ""); //("input-name", "My Input").ToString();

        //    //if (UseBootstrap)
        //    //{
        //    //    //m_newHtml = "<div class=\"form-group\"><input type=\"email\" class=\"form-control\" id=\"exampleInputEmail1\" placeholder=\"Enter email\"></div>";

        //    //    Console.WriteLine(this.Controls.Count);

        //    //    string m_html = ((HtmlForm)this.Controls[0].Controls[1]).InnerHtml;

        //    //    HtmlDocument htmlDoc = new HtmlDocument();
        //    //    htmlDoc.LoadHtml(m_html);

        //    //    //m_newHtml = "<span>" + m_newHtml  + "</span>";

        //    //    var inputs = htmlDoc.DocumentNode.Descendants("input");

        //    //    foreach (var input in inputs.ToList())
        //    //    {
        //    //        var newNode = HtmlNode.CreateNode(SetInputGroup1());
        //    //        input.ParentNode.ReplaceChild(newNode, input);
        //    //    }

        //    //    string p = string.Empty;
        //    //    using (StringWriter writer = new StringWriter())
        //    //    {
        //    //        htmlDoc.Save(writer);

        //    //        p = writer.GetStringBuilder().ToString();
        //    //    }

        //    //    output.Write(p);
        //    //}
        //    //else
        //    //{
        //    //    this.RenderChildren(output);
        //    //}
        //    //output.Write("<div class='container'>");
            
        //    //this.RenderChildren(output2);
        //    //output.Write("</div>");
        //}

        //protected override void Render(HtmlTextWriter writer)
        //{
        //    StringBuilder sb = new StringBuilder();

        //    HtmlTextWriter tw = new HtmlTextWriter(new StringWriter(sb));
        //    base.Render(tw);

        //    string InnerHtml = sb.ToString();

        //    if (this.UseBootstrap)
        //    {
        //        InnerHtml = Decorate(InnerHtml);
        //    }


        //    writer.Write(InnerHtml);
        //}

        public string Decorate(string html)
        {
            // grap the html content of the page...
            string retValue = string.Empty;

            HtmlNode.ElementsFlags.Remove("form");

            HtmlDocument htmlDoc = new HtmlDocument();
            htmlDoc.LoadHtml(html);

            // manipulate the html accordingly with the configuration...
            List<HtmlNode> m_nodes = null;

            // check if there are form tags to manipulate...
            var forms = htmlDoc.DocumentNode.Descendants("form");
            m_nodes = forms.ToList();

            var m_forms = this.m_elements.Tags.Where(x => x.GetType() == typeof(Form));
            if (m_forms.Any())
            {
                foreach (Form m_form in m_forms)
                {
                    var obj = m_nodes.Where(x => x.Id == m_form.RefId);
                    if (obj.Any())
                    {
                        HtmlNode node = obj.FirstOrDefault();

                        var newNode = HtmlNode.CreateNode(ConvertForm(node, m_form));

                        if (!m_form.Visible)
                        {
                            node.ParentNode.RemoveChild(node);
                        }
                        else
                        {
                            HtmlNode body = node.ParentNode;
                            node.ParentNode.RemoveChild(node);
                            body.AppendChild(newNode);
                        }
                    }
                }
            }

            // check if there are input tags to manipulate...
            var inputs = htmlDoc.DocumentNode.Descendants("input");
            m_nodes = inputs.ToList();

            var m_inputs = this.m_elements.Tags.Where(x => x.GetType() == typeof(Input));
            if (m_inputs.Any())
            {
                foreach (Input m_input in m_inputs)
                {
                    var obj = m_nodes.Where(x => x.Id == m_input.RefId);
                    if (obj.Any())
                    {
                        HtmlNode node = obj.FirstOrDefault();

                        var newNode = HtmlNode.CreateNode(ConvertInput(node, m_input));

                        if (!m_input.Visible)
                        {
                            node.ParentNode.RemoveChild(node);
                        }
                        else
                        {
                            node.ParentNode.ReplaceChild(newNode, node);
                        }
                    }
                }
            }

            // prepare the html to render...
            using (StringWriter writer = new StringWriter())
            {
                htmlDoc.Save(writer);

                retValue = writer.GetStringBuilder().ToString();
            }

            return retValue;
        }

        public string Decorate__(string html)
        {
            string retValue = string.Empty;

            HtmlDocument htmlDoc = new HtmlDocument();
            htmlDoc.LoadHtml(html);

            var linksOnPage = from tag in htmlDoc.DocumentNode.Descendants()
                              where tag.Name == "input" 
                              select new
                              {
                                  Text = tag.Id
                              }; 

                        //if((this.Elements.Forms != null) && (this.Elements.Forms.Count() > 0))
                        //{
                        //    var inputs = htmlDoc.DocumentNode.Descendants("input");

                        //    List<HtmlNode> m_nodes = inputs.ToList();

                        //    foreach (Form m_form in this.Elements.Forms)
                        //    {
                        //        var obj = m_nodes.Where(x => x.Id == m_form.Name);
                        //        if (obj.Any())
                        //        {
                        //            foreach (Input m_input in m_form.Inputs)
                        //            {
                        //                HtmlNode node = obj.FirstOrDefault();

                        //                var newNode = HtmlNode.CreateNode(SetInputGroup1(node.Id, node.Name,
                        //                             m_input.Placeholder, m_input.HasGroupBefore, m_input.HasGroupAfter));

                        //                if (!m_input.Visible)
                        //                {
                        //                    node.ParentNode.RemoveChild(node);
                        //                }
                        //                else
                        //                {
                        //                    node.ParentNode.ReplaceChild(newNode, node);
                        //                }
                        //            }
                        //        }
                        //    }
                        //}

            //foreach (Element m_element in this.Elements.Configuration)
            //{
            //    var obj = m_nodes.Where(x=>x.Id == m_element.Name);
            //    if (obj.Any())
            //    {
            //        HtmlNode node = obj.FirstOrDefault();

            //        var newNode = HtmlNode.CreateNode(SetInputGroup1(node.Id, node.Name, m_element.Placeholder));

            //        if (!m_element.Visible)
            //        {
            //            node.ParentNode.RemoveChild(node);
            //        }
            //        else
            //        {
            //            node.ParentNode.ReplaceChild(newNode, node);
            //        }
            //    }

            //    //foreach (var input in m_nodes)
            //    //{
            //    //    if ((input.Attributes["type"].Value == "text") ||
            //    //        (input.Attributes["type"].Value == "email") ||
            //    //        (input.Attributes["type"].Value == "password"))
            //    //    {
            //    //        var newNode = HtmlNode.CreateNode(SetInputGroup1(input.Id, input.Name));
            //    //        input.ParentNode.ReplaceChild(newNode, input);
            //    //    }
            //    //}
            //}

            //var tables = htmlDoc.DocumentNode.Descendants("table");
            //foreach (var table in tables.ToList())
            //{
            //    var newNode = HtmlNode.CreateNode(SetTable(table));
            //    table.ParentNode.ReplaceChild(newNode, table);
            //}


            using (StringWriter writer = new StringWriter())
            {
                htmlDoc.Save(writer);

                retValue = writer.GetStringBuilder().ToString();
            }

            return retValue;
        }

        protected override void OnInit(System.EventArgs e)
        {
            base.OnInit(e);

            // Initialize all child controls.
            this.CreateChildControls();
            this.ChildControlsCreated = true;
        }

        protected override void CreateChildControls()
        {
            // Remove any controls
            this.Controls.Clear();

            if (this.Content != null)
            {
                // Add all content to a container.
                var container = new Control();

                this.Content.InstantiateIn(container);

                // Add container to the control collection.
                this.Controls.Add(container);
            }
        }

        //protected override void OnPreRender(EventArgs e)
        //{
        //    string[] m_forms = this.Page.Request.Form.AllKeys;


        //    List<System.Web.UI.HtmlControls.HtmlInputControl> allControls = new List<System.Web.UI.HtmlControls.HtmlInputControl>();
        //    GetControlList<System.Web.UI.HtmlControls.HtmlInputControl>(Page.Controls, allControls);
        //    foreach (var childControl in allControls )
        //    {
        //    //     call for all controls of the page
        //    }

        //    Console.WriteLine(allControls.Count);
        //    //foreach (Control c in Page.Controls)
        //    //{
        //    //    if (c.GetType() != typeof(Bootstrapminator))
        //    //    {
        //    //        m_internalControlCollection.Add(c);
        //    //    }
        //    //}

        //    base.OnPreRender(e);
        //}

        //protected override void RenderContents(HtmlTextWriter output)
        //{
        //    output.Write(Text);
        //}

        //private void GetControlList<T>(ControlCollection controlCollection, List<T> resultCollection) where T : Control
        //{
        //    foreach (Control control in controlCollection)
        //    {
        //        //if (control.GetType() == typeof(T))
        //        if (control is T) // This is cleaner
        //            resultCollection.Add((T)control);

        //        if (control.HasControls())
        //            GetControlList(control.Controls, resultCollection);
        //    }
        //}

        public string SetInputGroup()
        {
            string retValue = string.Empty;

            StringBuilder sb = new StringBuilder();

            sb.Append("<div class=\"input-group\" style=\"padding:5px\">");
            sb.Append("<span class=\"input-group-addon\" id=\"basic-addon1\">@</span>");
            sb.Append("<input type=\"text\" class=\"form-control\" placeholder=\"Username\" aria-describedby=\"basic-addon1\">");
            sb.Append("</div>");

            retValue = sb.ToString();

            return retValue;
        }

        public string SetInputGroup1__(string id, string name, string placeholder = "", Icon before = Icon.None, Icon after = Icon.None)
        {
            string retValue = string.Empty;

            SimpleBootstrapHelper helper = new SimpleBootstrapHelper();

            retValue = helper.InputGroup().AddAttribute("style", "padding:5px")
                            .AddChild(helper.InputGroupAddon(helper.Icon(before)))
                            .AddChild(helper.Input(name).SetId(id).SetPlaceholder((string.IsNullOrWhiteSpace(placeholder) ? name : placeholder)))
                            .AddChild(helper.InputGroupAddon(helper.Icon(after)))
                            .ToHtmlString();

            retValue = retValue.Replace("\r\n", "");
            return retValue;
        }

        public string ConvertForm(HtmlNode node, Form form)
        {
            string retValue = string.Empty;

            var m_formInputElements = node.SelectNodes("//input");

            SimpleBootstrapHelper helper = new SimpleBootstrapHelper();

            var obj = helper.Form();

            switch (form.View)
            {
                case FormView.Vertical:
                    foreach (HtmlNode fie in m_formInputElements)
                    {
                        obj = obj.AddContent(fie.OuterHtml);
                    }
                    break;
                case FormView.Inline:
                    obj = obj.SetInline();
                    foreach (HtmlNode fie in m_formInputElements)
                    {
                        obj = obj.AddContent(fie.OuterHtml);
                    }
                    break;
                case FormView.Horizontal:
                    obj = obj.SetHorizontal();

                    foreach (HtmlNode fie in m_formInputElements)
                    {
                        obj = obj.AddChild(helper.FormGroup().AddContent(fie.OuterHtml));
                    }
                    break;
                default:
                    break;
            }
            
            retValue = obj.ToHtmlString();

            retValue = retValue.Replace("\r\n", "");

            return retValue;
        }

        public string ConvertInput(HtmlNode node, Input input)
        {
            string retValue = string.Empty;

            SimpleBootstrapHelper helper = new SimpleBootstrapHelper();

            ComponentBuilder<SimpleBootstrapConfig, FluentBootstrap.Forms.InputGroup> obj = helper.InputGroup().AddAttribute("style", "padding:5px");

            if (input.HasGroupBefore != Icon.None)
            {
                obj = obj.AddChild(helper.InputGroupAddon(helper.Icon(input.HasGroupBefore)));
            }

            obj = obj.AddChild(helper.Input(node.Name,input.Label).SetId(node.Id).SetPlaceholder((string.IsNullOrWhiteSpace(input.Placeholder) ? node.Name : input.Placeholder)));

            if (input.HasGroupAfter != Icon.None)
            {
                obj = obj.AddChild(helper.InputGroupAddon(helper.Icon(input.HasGroupAfter)));
            }

            retValue = obj.ToHtmlString();

            retValue = retValue.Replace("\r\n", "");
            return retValue;
        }

        public string SetInputGroup1(string id, string name, string placeholder="", Icon before=Icon.None, Icon after=Icon.None)
        {
            string retValue = string.Empty;

            SimpleBootstrapHelper helper = new SimpleBootstrapHelper();

            var obj = helper.InputGroup().AddAttribute("style", "padding:5px");

            if (before != Icon.None)
            {
                obj = obj.AddChild(helper.InputGroupAddon(helper.Icon(before)));
            }

            obj = obj.AddChild(helper.Input(name).SetId(id).SetPlaceholder((string.IsNullOrWhiteSpace(placeholder) ? name : placeholder)));

            if (after != Icon.None)
            {
                obj = obj.AddChild(helper.InputGroupAddon(helper.Icon(after)));
            }

            retValue = obj.ToHtmlString();

            retValue = retValue.Replace("\r\n", "");
            return retValue;
        }

        public string SetTable(HtmlNode table)
        {
            string retValue = string.Empty;

            SimpleBootstrapHelper helper = new SimpleBootstrapHelper();
            var nTable = helper.Table().SetStyle(FluentBootstrap.TableStyle.Striped);

            var header = helper.TableHeadSection();
            var trs = table.SelectNodes("tr");
            if (trs != null)
            {
                foreach (HtmlNode row in trs)
                {
                    var ths = row.SelectNodes("th");

                    if (ths != null)
                    {
                        foreach (HtmlNode th in ths)
                        {
                            header.AddChild(helper.TableData(th.InnerText));
                        }
                    }
                }
            }

            nTable.AddChild(header);

            foreach (HtmlNode row in table.SelectNodes("tr"))
            {
                var rowD = helper.TableRow();

                var tds = row.SelectNodes("td");

                if (tds != null)
                {
                    foreach (HtmlNode cell in row.SelectNodes("td"))
                    {
                        rowD.AddChild(helper.TableData(cell.InnerText));
                    }
                }

                nTable.AddChild(rowD);
            }

            retValue = nTable.ToHtmlString();

            retValue = retValue.Replace("\r\n", "");
            return retValue;
        }

    }
}
